package com.solarfridge.monitor.server;

import java.io.IOException;
import java.security.SecureRandom;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.solarfridge.monitor.client.DataService;
import com.solarfridge.monitor.shared.data.Fridge;
import com.solarfridge.monitor.shared.data.FridgeData;

/**
 * This servlets handles all of the post requests from the remote fridges and
 * logs the data. It should never be able to delete data or make large edits
 * to the recored as access to posting to this class does not require
 * authentication. <br>
 * 
 * If logging for a given fridge has been disabled, the request to store
 * data is simply ignored.
 * <br>
 * All requests to this class requesting to store data should have the following
 * keys: <br>
 * <code>
 * fridgeId <br>
 * time <br>
 * </code>
 */
@SuppressWarnings("serial")
public class FridgeReportingServlet extends HttpServlet{

	public static int RESULT_OK = 0;
	public static int RESULT_INVALID_ID = RESULT_OK + 1;
	public static int RESULT_BAD_PASSWORD = RESULT_INVALID_ID + 1;
	public static int RESULT_LOGGING_DISABLED = RESULT_BAD_PASSWORD + 1;
	public static int RESULT_MALFORMED = RESULT_LOGGING_DISABLED + 1;

	public static String TYPE_CHECK = "CONNECTION";
	public static String TYPE_SALT = "SALT";
	public static String TYPE_POST = "POST_DATA";

	public static String KEY_FRIDGE_ID = "FridgeId";
	public static String KEY_TYPE = "Type";
	public static String KEY_SALT = "Salt";
	public static String KEY_ATEMP = "Atemp";
	public static String KEY_FTEMP  = "Ftemp";
	public static String KEY_CTEMP = "Ctemp";
	public static String KEY_CSUN = "Csun";
	public static String KEY_TIME = "Time";
	public static String KEY_KEY = "Key";
	public static String KEY_RESULT = "Result";

	//Encryption
	public static final int SALT_LENGTH = 20;

	private SecureRandom mRandom = new SecureRandom();

	/**
	 * Create a remote service proxy to talk to the server-side Greeting service.
	 */
	private final DataService mDataService = new DataServiceImpl();
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
		throws ServletException, IOException {

		String type = req.getParameter(KEY_TYPE);
		
		if(type == null) {
			//TODO implement malformed
		} else if(type.equals(TYPE_CHECK)){
			String fridgeId = req.getParameter(KEY_FRIDGE_ID);
			resp.addHeader(KEY_FRIDGE_ID, fridgeId);
			resp.addHeader(KEY_TYPE, TYPE_CHECK);
		} else if (type.equals(TYPE_SALT)) {
			String fridgeId = req.getParameter(KEY_FRIDGE_ID);
			resp.addHeader(KEY_FRIDGE_ID, fridgeId);
			resp.addHeader(KEY_TYPE, TYPE_SALT);

			byte[] saltBytes = new byte[SALT_LENGTH];
			mRandom.nextBytes(saltBytes);
			String salt = new String(saltBytes);
			resp.addHeader(KEY_SALT, salt);

		} else if (type.equals(TYPE_POST)) {
			//Currently accepts any post regardless of proper
			//key
			String fridgeId = req.getParameter(KEY_FRIDGE_ID);			
			Fridge targetFridge = mDataService.getFridgeById(fridgeId);
			resp.addHeader(KEY_FRIDGE_ID, fridgeId);
			resp.addHeader(KEY_TYPE, TYPE_POST);
			
			if(targetFridge == null){
				resp.addHeader(KEY_RESULT, String.valueOf(RESULT_INVALID_ID));
				return;
			}
			
			if(!targetFridge.isLoggingEnabled()) {
				resp.addHeader(KEY_RESULT, String.valueOf(RESULT_LOGGING_DISABLED));
				return;
			}

			FridgeData data = constructFridgeData(req);
			if(data == null) {
				resp.addHeader(KEY_RESULT, String.valueOf(RESULT_MALFORMED));
			}
			
			//Set last checkin time, current temp, etc
			targetFridge.updateData(data);
			mDataService.recordData(data);
			
			resp.addHeader(KEY_RESULT, String.valueOf(RESULT_OK));
		} else {
			//TODO implement undefined behavior
		}		
	}
	
	/**
	 * 
	 * @param req
	 * @return Null is any error occurs during the process
	 */
	private FridgeData constructFridgeData(HttpServletRequest req) {
		String fridgeId = req.getParameter(KEY_FRIDGE_ID);
		double aTemp = Double.valueOf(req.getParameter(KEY_ATEMP));
		double cTemp = Double.valueOf(req.getParameter(KEY_CTEMP));
		double fTemp = Double.valueOf(req.getParameter(KEY_FTEMP));
		double cSun = Double.valueOf(req.getParameter(KEY_CSUN));
		long timeStamp = Long.valueOf(req.getParameter(KEY_TIME));
		
		FridgeData data = new FridgeData(fridgeId, aTemp, 
				cTemp, fTemp, cSun, timeStamp);
		
		return (data.isValid()) ? data : null;
	}
}	

